package com.mxx.common.utils;

import com.mxx.common.exception.NotFoundException;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author itzgyw
 * @Date 2020-03-30
 * @Time 18:31
 * @Description:
 */
@Slf4j
public class ClassUtil {

    public static boolean isSuperInterface(Class domainClass, Class superInterfaceClass) {
        return superInterfaceClass.isAssignableFrom(domainClass);
    }

    public static boolean isBaseClass(Class domainClass) {

        switch (domainClass.getName()) {
            case "java.lang.String":
            case "java.lang.Integer":
            case "java.lang.Long":
            case "java.lang.Short":
            case "java.lang.Byte":
            case "java.lang.Double":
            case "java.lang.Float":
            case "java.math.BigDecimal":
            case "java.time.LocalDate":
            case "java.time.LocalDateTime":
            case "java.time.LocalTime":
            case "int":
            case "long":
            case "short":
            case "byte":
            case "double":
            case "float":
                return true;
            default:
                return false;
        }
    }

    public static boolean isNumber(Object val) {
        if (Strings.isEmpty(val)) {
            return false;
        }
        try {
            if (val instanceof Number) {
                return true;
            }
            Long.parseLong(val.toString());
            return true;
        } catch (NumberFormatException ex) {
            return false;
        }
    }

    public static boolean isBoolean(Object val) {
        if (Strings.isEmpty(val)) {
            return false;
        }
        return "true".equalsIgnoreCase(val.toString()) || "false".equalsIgnoreCase(val.toString());
    }

    public static boolean isArray(Object object) {
        return Strings.isNotNull(object) && object.getClass().isArray();
    }

    public static boolean isAnnotation(Object object) {
        return Strings.isNotNull(object) && object.getClass().isAnnotation();
    }

    public static boolean isEnum(Object object) {
        return Strings.isNotNull(object) && object.getClass().isEnum();
    }


    public static boolean isDoubleNumber(Object val) {
        if (Strings.isEmpty(val)) {
            return false;
        }
        try {
            String strVal = val.toString();
            if (strVal.indexOf(".") != -1) {
                Double.parseDouble(strVal);
                return true;
            }
            return false;
        } catch (NumberFormatException ex) {
            return false;
        }
    }

    public static boolean isDomainOrSuper(Class domainClass, Class superInterfaceClass) {
        return domainClass.equals(superInterfaceClass) || superInterfaceClass.isAssignableFrom(domainClass);
    }

    public static Class forName(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException ex) {
            throw new NotFoundException(ex, "class not found --> %s", className);
        }
    }

    public static List<Method> getMethodListWithPrefix(Class classes, String prefix) {
        List<Method> methodList = new ArrayList<>();
        getMethodWithPrefix(methodList, classes, prefix);
        return methodList;
    }

    public static Method[] getMethodWithPrefix(Class classes, String prefix) {
        List<Method> methodList = getMethodListWithPrefix(classes, prefix);
        return methodList.toArray(new Method[methodList.size()]);
    }

    public static void getMethodWithPrefix(List<Method> methodArrays, Class classes, String prefix) {
        Method[] methods = classes.getMethods();
        for (Method method : methods) {
            if (method.getName().startsWith(prefix)) {
                methodArrays.add(method);
            }
        }
        if (classes.getSuperclass() != null) {
            getMethodWithPrefix(methodArrays, classes.getSuperclass(), prefix);
        }
    }

    public static List<Method> getMethodListWithSuffix(Class classes, String prefix) {
        List<Method> methodList = new ArrayList<>();
        getMethodWithPrefix(methodList, classes, prefix);
        return methodList;
    }

    public static Method[] getMethodWithSuffix(Class classes, String prefix) {
        List<Method> methodList = getMethodListWithSuffix(classes, prefix);
        return methodList.toArray(new Method[methodList.size()]);
    }

    public static void getMethodWithSuffix(List<Method> methodArrays, Class classes, String suffix) {
        Method[] methods = classes.getMethods();
        for (Method method : methods) {
            if (method.getName().endsWith(suffix)) {
                methodArrays.add(method);
            }
        }
        if (classes.getSuperclass() != null) {
            getMethodWithSuffix(methodArrays, classes.getSuperclass(), suffix);
        }
    }

    public static List<Field> getFieldListWithPrefix(Class classes, String prefix) {
        List<Field> fieldList = new ArrayList<>();
        getFieldWithPrefix(fieldList, classes, prefix);
        return fieldList;
    }

    public static Field[] getFieldWithPrefix(Class classes, String prefix) {
        List<Field> fieldList = getFieldListWithPrefix(classes, prefix);
        return fieldList.toArray(new Field[fieldList.size()]);
    }

    public static void getFieldWithPrefix(List<Field> fieldArrays, Class classes, String prefix) {
        Field[] fields = classes.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().startsWith(prefix)) {
                fieldArrays.add(field);
            }
        }
        if (classes.getSuperclass() != null) {
            getFieldWithPrefix(fieldArrays, classes.getSuperclass(), prefix);
        }
    }

    public static List<Field> getFieldListWithSuffix(Class classes, String suffix) {
        List<Field> fieldList = new ArrayList<>();
        getFieldWithSuffix(fieldList, classes, suffix);
        return fieldList;
    }

    public static Field[] getFieldWithSuffix(Class classes, String suffix) {
        List<Field> fieldList = getFieldListWithSuffix(classes, suffix);
        return fieldList.toArray(new Field[fieldList.size()]);
    }

    public static void getFieldWithSuffix(List<Field> fieldArrays, Class classes, String suffix) {
        Field[] fields = classes.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().startsWith(suffix)) {
                fieldArrays.add(field);
            }
        }
        if (classes.getSuperclass() != null) {
            getFieldWithSuffix(fieldArrays, classes.getSuperclass(), suffix);
        }
    }


    public static <T extends Annotation> List<Field> getFieldListWithAnnotation(Class classes, Class<T> annotationClass) {
        List<Field> fieldList = new ArrayList<>();
        getFieldWithAnnotation(fieldList, classes, annotationClass);
        return fieldList;
    }

    public static <T extends Annotation> Field[] getFieldWithAnnotation(Class classes, Class<T> annotationClass) {
        List<Field> fieldList = getFieldListWithAnnotation(classes, annotationClass);
        return fieldList.toArray(new Field[fieldList.size()]);
    }


    public static <T extends Annotation> void getFieldWithAnnotation(List<Field> fieldArrays, Class classes, Class<T> annotationClass) {
        Field[] fields = classes.getDeclaredFields();
        for (Field field : fields) {
            if (field.getAnnotation(annotationClass) != null) {
                fieldArrays.add(field);
            }
        }
        if (classes.getSuperclass() != null) {
            getFieldWithAnnotation(fieldArrays, classes.getSuperclass(), annotationClass);
        }
    }

    public static <T extends Annotation> List<Method> getMethodListWithAnnotation(Class classes, Class<T> annotationClass) {
        List<Method> fieldList = new ArrayList<>();
        getMethodWithAnnotation(fieldList, classes, annotationClass);
        return fieldList;
    }

    public static <T extends Annotation> Method[] getMethodWithAnnotation(Class classes, Class<T> annotationClass) {
        List<Method> methodList = getMethodListWithAnnotation(classes, annotationClass);
        return methodList.toArray(new Method[methodList.size()]);
    }

    public static <T extends Annotation> void getMethodWithAnnotation(List<Method> methodArrays, Class classes, Class<T> annotationClass) {
        Method[] methods = classes.getMethods();
        for (Method method : methods) {
            if (Modifier.isPublic(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) {
                if (method.getAnnotation(annotationClass) != null) {
                    methodArrays.add(method);
                }
            }

        }
        if (classes.getSuperclass() != null) {
            getMethodWithAnnotation(methodArrays, classes.getSuperclass(), annotationClass);
        }
    }

    public static <T extends Annotation> T getAnnotation(Method method, Class<T> annotationClass) {
        return method.getAnnotation(annotationClass);
    }


    public static Object getFieldValue(Object data, Field field) {
        try {
            return field.get(data);
        } catch (Exception ex) {
            log.error("get fieldValue Exception", ex);
            return null;
        }
    }

    public static boolean setFieldValue(Object data, Field field, Object val) {
        try {
            field.set(data, val);
            return true;
        } catch (Exception ex) {
            log.error("set fieldValue Exception", ex);
            return false;
        }
    }



}
